#pragma once 

#include "graphics/Shader.h"
#include <list>
/*
	Add alpha blending with particle fading 
	Add geometry shader quads 
	Add particle textures 

	TODO: 
	- Do we need to blend particles against background with non-additive blending?
		- Maybe need to render particles to texture and do regular alpha blending of texture again scene	
			- How to handle z-buffer particle rejection 
				- Can I attach scene depth buffer before rendering?
	- Add emitters managed by PS for explosions etc 
	
*/

struct ParticleVertex
{
	ParticleVertex () : 
		pos(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)), vel(glm::vec3(0.0f, 0.0f, 0.0f)), color(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)), props(glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)) 
	{}
	ParticleVertex (const glm::vec4 & pos, const glm::vec3 & vel, const glm::vec4 & color, const glm::vec4 & props) :
		pos(pos), vel(vel), color(color), props(props) {}

	glm::vec4 pos;
	glm::vec3 vel;
	glm::vec4 color;
	glm::vec4 props;
};

class ParticleSystem {
public:
	enum ParticleEvo { out_linear=0, out_quadratic, inout_linear, inout_quadratic};
	struct ParticleStore {
		ParticleStore(float ttl, unsigned int count) :
			ttl(ttl), count(count)
		{}

		float ttl;
		unsigned int count;
	};
	struct GLBuf { GLuint vao; GLuint vbo; };

	ParticleSystem();
	void AddParticles(unsigned int count, float ttl, ParticleEvo evo, const glm::vec3 & pos, float posRand, float size, const glm::vec3 & vel, float velRand, std::vector<glm::vec4> & colors);
	void UpdateAndDraw(float dt, const glm::mat4 & viewMatrix);
	void BlueExplosion(const glm::vec3 & pos, float size);

	GLBuf& getBufOut() { return glBufs[bufIdx]; }
	GLBuf& getBufIn() { return glBufs[1-bufIdx]; }
	void advanceBuf() { bufIdx = (bufIdx+1) % 2; }
	
private:
	GLBuf glBufs[2];
	int activePtr;
	int freePtr;
	int bufIdx;
	unsigned int bufSize;
	Shader* renderShader;
	Shader* simShader;
	std::list<ParticleStore> particleStoreList;

};